/**
 * 
 */
package wpmp.security.mgr.web;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import wcommons.lang.NumberUtils;
import wpmp.extjs3.ExtjsUtils;
import wpmp.extjs3.data.Form;
import wpmp.extjs3.data.JsonStore;
import wpmp.extjs3.data.TreeNode;
import wpmp.security.client.internal.PmpResourceUtils;
import wpmp.security.mgr.Statics;
import wpmp.security.mgr.base.BaseAction;
import wpmp.security.mgr.base.DefaultBaseAction;
import wpmp.security.mgr.entity.Operation;
import wpmp.security.mgr.entity.Resource;
import wpmp.security.mgr.entity.Role;
import wpmp.security.mgr.entity.User;
import wpmp.security.mgr.service.OperationService;
import wpmp.security.mgr.service.ResourceService;
import wpmp.security.mgr.service.RoleService;
import wpmp.security.mgr.service.UserService;
import wpmp.utils.quickbean.UserPermission;

/**
 * @author Wayne.Wang<5waynewang@gmail.com>
 * @since 10:38:13 PM Mar 15, 2013
 */
@Action("role")
@Results({ @Result(name = BaseAction.LIST, location = "/WEB-INF/role/list.jsp"),
		@Result(name = BaseAction.INPUT, location = "/WEB-INF/role/input.jsp"),
		@Result(name = RoleAction.SELECT, location = "/WEB-INF/role/select.jsp"),
		@Result(name = RoleAction.LIST_RESOURCE, location = "/WEB-INF/role/listResource.jsp"),
		@Result(name = RoleAction.LIST_USER, location = "/WEB-INF/role/listUser.jsp") })
public class RoleAction extends DefaultBaseAction<Role> {

	private static final long serialVersionUID = 1L;

	private static final Logger LOG = LoggerFactory.getLogger(RoleAction.class);

	static final String LIST_RESOURCE = "listResource";
	static final String LIST_USER = "listUser";
	static final String SELECT = "select";

	private RoleService service;
	private ResourceService resourceService;
	private UserService userService;
	private OperationService operationService;

	@Autowired
	public void setService(RoleService service) {
		this.service = service;
	}

	@Autowired
	public void setResourceService(ResourceService resourceService) {
		this.resourceService = resourceService;
	}

	@Autowired
	public void setUserService(UserService userService) {
		this.userService = userService;
	}

	@Autowired
	public void setOperationService(OperationService operationService) {
		this.operationService = operationService;
	}

	public String select() throws Exception {
		return SELECT;
	}

	@Override
	public String list() throws Exception {
		// 根节点名称
		this.getRequest().setAttribute("ROOT_NAME", service.get(Statics.ROOT_ID).getName());
		return LIST;
	}

	public void listJSON() throws Exception {
		final HttpServletRequest req = this.getRequest();

		Long id = entity.getId();
		if (!NumberUtils.gtZero(id)) {
			String node = req.getParameter("node");
			if (StringUtils.isNotBlank(node)) {
				id = Long.valueOf(node);
			}
		}
		if (!NumberUtils.gtZero(id)) {
			id = Statics.ROOT_ID;// root 节点
		}
		final SqlRowSet rs = service.queryChildrenIsLeaf(id);
		final List<TreeNode> treeNodes = new ArrayList<TreeNode>();
		for (Role child : service.getChildren(id)) {
			final TreeNode treeNode = new TreeNode();
			treeNode.setId(child.getId().toString());
			treeNode.setText(child.getName());

			boolean isLeaf = true;
			while (rs.next()) {
				if (NumberUtils.eq(child.getId(), rs.getLong("id"))) {
					isLeaf = rs.getBoolean("is_leaf");
				}
			}
			rs.beforeFirst();
			treeNode.setLeaf(isLeaf);
			treeNode.addAttribute("orderNum", child.getOrderNum());
			treeNodes.add(treeNode);
		}

		this.renderJson(TreeNode.toJSONString(treeNodes));
	}

	@Override
	public String input() throws Exception {
		final HttpServletRequest req = this.getRequest();

		String parentName = null;
		Role parent = null;
		if (NumberUtils.gtZero(entity.getParentId())) {
			parent = service.get(entity.getParentId());
		}
		else if (NumberUtils.gtZero(entity.getId())) {
			parent = service.getParent(entity.getId());
		}
		if (parent != null) {
			parentName = parent.getName();
		}
		req.setAttribute("PARENT_NAME", StringUtils.trimToEmpty(parentName));

		return INPUT;
	}

	public void getJSON() throws Exception {
		final Role result = service.get(entity.getId());

		if (LOG.isDebugEnabled()) {
			LOG.debug("{}", result);
		}

		if (result == null) {
			LOG.warn("can not found Role by id[{}]", entity.getId());

			this.renderJson(ExtjsUtils.getDefaultErrorFormJSONString(Statics.DEFAULT_ERROR_MSG));
			return;
		}

		final String jsonString = Form.newInstance(result).toJSONString();

		if (LOG.isDebugEnabled()) {
			LOG.debug(jsonString);
		}

		this.renderJson(jsonString);
	}

	public void insertJSON() throws Exception {
		this.renderJson(service.insert(entity).toJSONString());
	}

	public void updateJSON() throws Exception {
		this.renderJson(service.update(entity).toJSONString());
	}

	public void deleteJSON() throws Exception {
		this.renderJson(service.delete(entity.getId()).toJSONString());
	}

	public void sortJSON() throws Exception {
		this.renderJson(service.sort(entity).toJSONString());
	}

	@Override
	public Role getModel0() {
		if (entity == null) {
			entity = new Role();
		}
		return entity;
	}

	/**
	 * 至授权资源的页面
	 * 
	 * @return
	 */
	public String listResource() {
		return LIST_RESOURCE;
	}

	//	private boolean hasPermission(final UserPermission permission, final String baseUrl) {
	//		if (permission.getUser().isAdmin()) {
	//			return true;
	//		}
	//		for (UserPermission.Entry entry : permission.getResources()) {
	//			if (StringUtils.equals(entry.getBaseUrl(), baseUrl)) {
	//				return true;
	//			}
	//		}
	//		return false;
	//	}
	//
	//	private boolean hasPermission(final UserPermission permission, final String baseUrl, final String operations) {
	//		if (permission.getUser().isAdmin()) {
	//			return true;
	//		}
	//		for (UserPermission.Entry entry : permission.getResources()) {
	//			if (StringUtils.equals(entry.getBaseUrl(), baseUrl)
	//					&& StringUtils.equals(entry.getOperations(), operations)) {
	//				return true;
	//			}
	//		}
	//		return false;
	//	}

	private boolean hasPermission(final SqlRowSet rs, final Long resourceId, final Long operationId) {
		rs.beforeFirst();
		while (rs.next()) {
			if (rs.getLong("resource_id") == resourceId && rs.getLong("operation_id") == operationId) {
				return true;
			}
		}
		return false;
	}

	List<TreeNode> getResources(final UserPermission userPermission, final Long roleId, final Long resourceId) {
		final boolean isAdmin = userPermission.getUser().isAdmin();

		final List<TreeNode> treeNodes = new LinkedList<TreeNode>();

		// 当前用户有权限的资源、操作
		// {resource_id,operation_id,level,is_public}
		final SqlRowSet uroRs = resourceService.queryUserResourceOperationForRowSet(userPermission.getUser()
				.getLoginName());

		// 当前角色有权限的资源、操作列表
		// {resource_id,operation_id,level,is_public}
		final SqlRowSet rs = service.queryRoleResourceOperationForRowSet(roleId);

		// 获取子资源列表
		final List<Resource> children = resourceService.getChildren(resourceId);

		for (Resource child : children) {
			// 公共资源隐藏，不需要授权
			if (child.getIsPublic()) {
				continue;
			}
			//			// 此叶子节点没有权限
			//			if (child.getIsLeaf() && !hasPermission(userPermission, child.getBaseUrl())) {
			//				continue;
			//			}

			final TreeNode treeNode = new TreeNode();
			treeNode.setId(child.getId().toString());
			treeNode.setLeaf(child.getIsLeaf());

			int index = 0;
			final StringBuilder sb = new StringBuilder();
			// 只有叶子节点才设置操作类型
			if (child.getIsLeaf()) {
				// 获取资源 的操作类型 列表
				final List<Operation> operations = operationService.getResourceOperations(child.getId());
				if (CollectionUtils.isNotEmpty(operations)) {
					for (Operation e : operations) {
						// 当前用户没权限，则不显示
						if (!isAdmin && !hasPermission(uroRs, child.getId(), e.getId())) {
							continue;
						}
						// 当前角色有没分配此资源操作，如果已分配则选中
						boolean checked = false; // 默认未选中
						rs.beforeFirst();
						while (rs.next()) {
							if (NumberUtils.eq(child.getId(), rs.getLong("resource_id"))
									&& NumberUtils.eq(e.getId(), rs.getLong("operation_id"))) {
								++index;
								checked = true;
								break;
							}
						}
						sb.append(getCheckbox(e.getName(), treeNode.getId(), e.getId(), checked));
					}
					// 该资源下无操作可分配，则隐藏
					if (sb.length() <= 0) {
						continue;
					}
				}
			}
			// 非叶子节点，如果其子节点都没有权限操作，则不显示
			else if (!isAdmin) {
				uroRs.beforeFirst();
				boolean hasPermission = false;
				while (uroRs.next()) {
					// 忽略公共资源
					if (uroRs.getBoolean("is_public")) {
						continue;
					}
					final String level = uroRs.getString("level");
					if (!child.getLevel().equals(level) && level.startsWith(child.getLevel())) {
						hasPermission = true;
						break;
					}
				}
				// 没有权限，则忽略
				if (!hasPermission) {
					continue;
				}
			}

			// 是否需要展开，如果其下级节点需要选中，则展开
			boolean expanded = false;
			// 判断节点是否需要展开
			rs.beforeFirst();
			while (rs.next()) {
				// 忽略公共资源
				if (rs.getBoolean("is_public")) {
					continue;
				}
				final String level = rs.getString("level");
				if (!child.getLevel().equals(level) && level.startsWith(child.getLevel())) {
					expanded = true;
					break;
				}
			}
			if (sb.length() > 0) {
				treeNode.setText(sb.insert(0, "&nbsp;&nbsp;&nbsp;&nbsp;").insert(0, child.getName()).toString());
			}
			else {
				treeNode.setText(child.getName());
			}

			treeNode.addAttribute("checked", index > 0);
			treeNode.addAttribute("expanded", expanded);
			treeNode.addAttribute("orderNum", child.getOrderNum());
			treeNodes.add(treeNode);
		}
		return treeNodes;
	}

	public void listResourceJSON() {
		final Long roleId = entity.getId();
		if (!NumberUtils.gtZero(roleId)) {
			LOG.warn("roleId is null");
			this.renderJson("[]");
			return;
		}

		final HttpServletRequest req = this.getRequest();

		Long resourceId = entity.getResourceId();
		if (!NumberUtils.gtZero(resourceId)) {
			String node = req.getParameter("node");
			if (StringUtils.isNotBlank(node)) {
				resourceId = Long.valueOf(node);
			}
		}
		if (!NumberUtils.gtZero(resourceId)) {
			resourceId = Statics.ROOT_ID;// root 节点
		}

		// 当前登录人员有权限的资源
		final UserPermission userPermission = PmpResourceUtils.getAndSetUserPermission(req);

		final List<TreeNode> treeNodes = getResources(userPermission, roleId, resourceId);

		this.renderJson(TreeNode.toJSONString(treeNodes));
	}

	/**
	 * 获取HTML checkbox
	 * 
	 * @param viewText
	 * @param name
	 * @param value
	 * @param checked
	 * @return
	 */
	private StringBuilder getCheckbox(String viewText, String name, Long value, boolean checked) {
		StringBuilder sb = new StringBuilder();
		sb.append("<input type='checkbox' ");
		sb.append(" name='checkbox_operation_").append(name).append("' ");
		sb.append(" value=").append(value);
		sb.append(checked ? " checked" : "");
		sb.append(">").append(viewText);
		return sb;
	}

	/**
	 * 授权资源
	 * 
	 * @throws Exception
	 */
	public void resetResourceJSON() throws Exception {
		final HttpServletRequest req = this.getRequest();
		final String resourceJSONString = req.getParameter("resourceJSONString");
		this.renderJson(service.resetResource(entity, resourceJSONString).toJSONString());
	}

	/**
	 * 至授权用户的页面
	 * 
	 * @return
	 */
	public String listUser() {
		return LIST_USER;
	}

	public void listUserJSON() {
		if (!NumberUtils.gtZero(entity.getId())) {
			LOG.warn("roleId is null");
			this.renderJson("[]");
			return;
		}
		final HttpServletRequest req = this.getRequest();

		final User user = new User();
		user.setUserName(req.getParameter("userName"));
		user.setRoleId(entity.getId());
		user.setHasRole(BooleanUtils.toBooleanObject(req.getParameter("hasRole")));

		final int total = userService.countAuth(user);
		if (total == 0) {
			this.renderJson(JsonStore.EMPTY.toJSONString());
			return;
		}

		final List<User> records = userService.listAuth(user, page);

		this.renderJson(new JsonStore<User>(total, records).toJSONString());
	}

	/**
	 * 授权用户
	 */
	public void addUserJSON() {
		this.renderJson(service.addUser(entity.getId(), entity.getUserIds()).toJSONString());
	}

	/**
	 * 取消授权
	 */
	public void removeUserJSON() {
		this.renderJson(service.removeUser(entity.getId(), entity.getUserIds()).toJSONString());
	}

}
